import os, socket, shutil
import gradio as gr
import pandas as pd
from datetime import date, datetime, time


# ---------------- 端口自动避让 ----------------
def pick_port(preferred=(7861, 7862)):
    for p in preferred:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            try:
                s.bind(("0.0.0.0", p))
                return p
            except OSError:
                continue
    raise SystemExit("7861 与 7862 均被占用，请手动指定端口")


# ---------------- 缓存上传文件 ----------------
CACHE_FILE = "cache.xlsx"


def upload_excel(file_obj):
    if file_obj is None:
        return "请先上传文件"
    shutil.copy(file_obj.name, CACHE_FILE)
    return "文件已缓存"


# ---------------- 三个时间段的统计函数 --------------------


def stat_morning():
    # 未打卡则是空
    # 已经打卡但是时间在8点40分以后则迟到
    file_path = 'cache.xlsx'
    df = pd.read_excel(file_path, header=1)
    late_or_empty = []
    late = []

    for _, row in df.iterrows():
        name = row.get('姓名')
        if name in ['陈燕','廖宇翔']:
            continue
        clock1 = row.get('上班1打卡时间')
        if should_mark_morning(clock1):
            late_or_empty.append(name)
        if should_mark_morning_late(clock1):
            late.append(name)
    late_or_empty_student = "、".join(late_or_empty)
    late_student = "、".join(late)
    return_str = f"早上迟到或者没来的同学有:\n{late_or_empty_student}\n其中迟到的同学有:\n{late_student}"
    return return_str


def should_mark_morning_late(clock_str):
    if pd.isna(clock_str) or str(clock_str).strip() == '' or str(clock_str).strip() == '-':
        # 上班1打卡时间 为空
        return False
    try:
        t = datetime.strptime(str(clock_str).strip(), '%H:%M').time()
        # 上班1打卡时间 >8:40 True
        # 上班1打卡时间 <8:40 False
        return t > time(8, 40)
    except Exception:
        # 解析失败也当成异常处理
        return True


def should_mark_morning(clock_str):
    """
    返回 True 表示需要输出该名字（没来或者迟到了）：
    1) 空值；2) 时间 > 08:40
    """
    if pd.isna(clock_str) or str(clock_str).strip() == '' or str(clock_str).strip() == '-':
        # 上班1打卡时间 为空
        return True
    try:
        t = datetime.strptime(str(clock_str).strip(), '%H:%M').time()
        # 上班1打卡时间 >8:40 True
        # 上班1打卡时间 <8:40 False
        return t > time(8, 40)
    except Exception:
        # 解析失败也当成异常处理
        return True


def stat_afternoon():
    # 未打卡则是空
    # 第一次打卡时间在12点到14点40算正常
    # 第三次打卡时间在12点到14点40算正常
    # 其他都算迟到
    file_path = 'cache.xlsx'
    df = pd.read_excel(file_path, header=1)
    late_or_empty = []
    late = []

    for _, row in df.iterrows():
        name = row.get('姓名')
        if name in ['陈燕','廖宇翔']:
            continue
        clock1 = row.get('上班1打卡时间')
        clock2 = row.get('上班2打卡时间')
        if should_mark_afternoon(clock1, clock2):
            late_or_empty.append(name)
        if should_mark_afternoon_late(clock1, clock2):
            late.append(name)
    late_or_empty_student = "、".join(late_or_empty)
    late_student = "、".join(late)
    return_str = f"下午迟到或没来的同学有:\n{late_or_empty_student}\n其中迟到的同学有:\n{late_student}"
    return return_str


def should_mark_afternoon_late(clock1, clock2):
    try:
        # if pd.isna(clock1) or str(clock1).strip() == '' or str(clock1).strip() == '-':
        #     # 上班1打卡时间 为空
        #     return False
        #
        # t1 = datetime.strptime(str(clock1).strip(), '%H:%M').time()
        # if time(12, 00) < t1 < time(14, 40):
        #     # 上班1打卡时间 在12点到2点40 则算成功上班
        #     return False

        if pd.isna(clock2) or str(clock2).strip() == '' or str(clock2).strip() == '-':
            # 上班2打卡时间 为空
            return False

        t2 = datetime.strptime(str(clock2).strip(), '%H:%M').time()
        if time(12, 00) < t2 < time(14, 40):
            # 上班2打卡时间 在12点到2点40 则算成功上班
            return False
        return True
    except Exception:
        # 解析失败也当成异常处理
        return True


def should_mark_afternoon(clock1, clock2):
    """
    返回 True 表示需要输出该名字（没来或者迟到了）：
    1) 空值；2) 时间1和时间2都不在12点到14点40
    """
    try:
        # if pd.isna(clock1) or str(clock1).strip() == '' or str(clock1).strip() == '-':
        #     # 上班1打卡时间 为空
        #     return True
        #
        # t1 = datetime.strptime(str(clock1).strip(), '%H:%M').time()
        # # 上班1打卡时间 在12点到2点40 则算成功上班
        # if time(12, 00) < t1 < time(14, 40):
        #     return False

        if pd.isna(clock2) or str(clock2).strip() == '' or str(clock2).strip() == '-':
            # 上班2打卡时间 为空
            return True

        t2 = datetime.strptime(str(clock2).strip(), '%H:%M').time()
        if time(12, 00) < t2 < time(14, 40):
            # 上班2打卡时间 在12点到2点40 则算成功上班
            return False
        return True
    except Exception:
        # 解析失败也当成异常处理
        return True


def stat_night():
    # 未打卡则是空
    # 第一次打卡时间在17点到19点40算正常
    # 第三次打卡时间在17点到19点40算正常
    # 第五次打卡时间在17点到19点40算正常

    # 其他都算迟到
    file_path = 'cache.xlsx'
    df = pd.read_excel(file_path, header=1)
    late_or_empty = []
    late = []

    for _, row in df.iterrows():
        name = row.get('姓名')
        if name in ['陈燕','廖宇翔']:
            continue
        clock1 = row.get('上班1打卡时间')
        clock2 = row.get('上班2打卡时间')
        clock3 = row.get('上班3打卡时间')
        if should_mark_evening(clock1, clock2, clock3):
            late_or_empty.append(name)
        if should_mark_evening_late(clock1, clock2, clock3):
            late.append(name)
    late_or_empty_student = "、".join(late_or_empty)
    late_student = "、".join(late)

    return_str = f"晚上迟到或者没来的同学有:\n{late_or_empty_student}\n其中迟到的同学有:\n{late_student}"
    return return_str


def should_mark_evening_late(clock1, clock2, clock3):
    try:
        # if pd.isna(clock1) or str(clock1).strip() == '' or str(clock1).strip() == '-':
        #     # 上班1打卡时间 为空
        #     return False
        #
        # t1 = datetime.strptime(str(clock1).strip(), '%H:%M').time()
        # if time(17, 00) < t1 < time(19, 40):
        #     # 上班1打卡时间 在17点到7点40 则算成功上班
        #     return False
        #
        # if pd.isna(clock2) or str(clock2).strip() == '' or str(clock2).strip() == '-':
        #     # 上班2打卡时间 为空
        #     return False
        #
        # t2 = datetime.strptime(str(clock2).strip(), '%H:%M').time()
        # if time(17, 00) < t2 < time(19, 40):
        #     # 上班2打卡时间 在17点到7点40 则算成功上班
        #     return False

        if pd.isna(clock3) or str(clock3).strip() == '' or str(clock3).strip() == '-':
            # 上班3打卡时间 为空
            return False

        t3 = datetime.strptime(str(clock3).strip(), '%H:%M').time()
        if time(17, 00) < t3 < time(19, 40):
            # 上班3打卡时间 在17点到7点40 则算成功上班
            return False
        return True
    except Exception:
        # 解析失败也当成异常处理
        return True


def should_mark_evening(clock1, clock2, clock3):
    """
    返回 True 表示需要输出该名字（迟到了）：
    1) 空值；2) 时间1和时间2和时间3都不在17点到19点40
    """
    try:
        # if pd.isna(clock1) or str(clock1).strip() == '' or str(clock1).strip() == '-':
        #     # 上班1打卡时间 为空
        #     return True
        #
        # t1 = datetime.strptime(str(clock1).strip(), '%H:%M').time()
        # if time(17, 00) < t1 < time(19, 40):
        #     # 上班1打卡时间 在17点到7点40 则算成功上班
        #     return False
        #
        # if pd.isna(clock2) or str(clock2).strip() == '' or str(clock2).strip() == '-':
        #     # 上班2打卡时间 为空
        #     return True
        #
        # t2 = datetime.strptime(str(clock2).strip(), '%H:%M').time()
        # if time(17, 00) < t2 < time(19, 40):
        #     # 上班2打卡时间 在17点到7点40 则算成功上班
        #     return False

        if pd.isna(clock3) or str(clock3).strip() == '' or str(clock3).strip() == '-':
            # 上班3打卡时间 为空
            return True

        t3 = datetime.strptime(str(clock3).strip(), '%H:%M').time()
        if time(17, 00) < t3 < time(19, 40):
            # 上班3打卡时间 在17点到7点40 则算成功上班
            return False
        return True
    except Exception:
        # 解析失败也当成异常处理
        return True


# ---------------- 页面布局 --------------------
with gr.Blocks(title="签到统计") as demo:
    gr.Markdown("### 签到统计面板")

    with gr.Row():
        upload_btn = gr.File(label="上传 Excel 表格", file_types=[".xlsx"])
        upload_info = gr.Textbox(label="上传状态", interactive=False)

    with gr.Row():
        btn_am = gr.Button("上午签到统计")
        btn_pm = gr.Button("下午签到统计")
        btn_night = gr.Button("晚上签到统计")

    output = gr.Textbox(label="统计结果", interactive=False, lines=5, max_lines=10)

    # 绑定事件
    upload_btn.upload(upload_excel, upload_btn, upload_info)
    btn_am.click(stat_morning, [], output)  # 上午按钮绑定上午统计函数
    btn_pm.click(stat_afternoon, [], output)  # 下午按钮绑定下午统计函数
    btn_night.click(stat_night, [], output)  # 晚上按钮绑定晚上统计函数

# ---------------- 启动 ------------------------
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=pick_port(),
        show_api=False,
        share=False
    )
